package org.apache.ocean.main.client.span;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.ocean.main.util.CElement;
import org.apache.ocean.main.util.XMLUtil;
import org.jdom.Element;

public class SpanClient {

	public static abstract class SpanQuery implements CElement {

	}

	public static SpanQuery getSpanQuery(Element element) throws Exception {
		String name = element.getName();
		if (StringUtils.equals("spanorquery", name)) {
			return new SpanOrQuery(element);
		} else if (StringUtils.equals("spannotquery", name)) {
			return new SpanNotQuery(element);
		} else if (StringUtils.equals("spannearquery", name)) {
			return new SpanNearQuery(element);
		} else if (StringUtils.equals("spanfirstquery", name)) {
			return new SpanFirstQuery(element);
		} else if (StringUtils.equals("spantermquery", name)) {
			return new SpanTermQuery(element);
		} else {
			throw new Exception("unknown span query: " + name);
		}
	}
  
	public static class SpanTermQuery extends SpanQuery {
		private String field;
		private String text;
		
		public SpanTermQuery(Element element) throws Exception {
			field = XMLUtil.getChildText("field", element);
			text = XMLUtil.getChildText("text", element);
		}
		
		public Element toElement() throws Exception {
			Element element = new Element("spantermquery");
			XMLUtil.createTextElement("field", field, element);
			XMLUtil.createTextElement("text", text, element);
			return element;
		}
		
		public SpanTermQuery(String field, String text) {
			this.field = field;
			this.text = text;
		}

		public String getField() {
			return field;
		}

		public String getText() {
			return text;
		}
	}
	
	public static class SpanOrQuery extends SpanQuery {
		private SpanQuery[] clauses;

		public SpanOrQuery(Element element) throws Exception {
			List<Element> children = XMLUtil.getChildren(element);
			SpanQuery[] clauses = new SpanQuery[children.size()];
			for (int x = 0; x < children.size(); x++) {
				clauses[x] = getSpanQuery(children.get(x));
			}
		}

		public SpanOrQuery(SpanQuery[] clauses) {
			this.clauses = clauses;
		}

		public Element toElement() throws Exception {
			Element element = new Element("spanorquery");
			for (SpanQuery spanQuery : clauses) {
				element.addContent(spanQuery.toElement());
			}
			return element;
		}

		public SpanQuery[] getClauses() {
			return clauses;
		}
	}

	public static class SpanNotQuery extends SpanQuery {
		private SpanQuery include;
		private SpanQuery exclude;

		public SpanNotQuery(Element element) throws Exception {
			Element includeElement = element.getChild("include");
			include = getSpanQuery(XMLUtil.getFirstChild(includeElement));
			Element excludeElement = element.getChild("exclude");
			exclude = getSpanQuery(XMLUtil.getFirstChild(excludeElement));
		}

		public SpanNotQuery(SpanQuery include, SpanQuery exclude) {
			this.include = include;
			this.exclude = exclude;
		}

		public Element toElement() throws Exception {
			Element element = new Element("spannotquery");
			Element includeElement = new Element("include");
			includeElement.addContent(include.toElement());
			Element excludeElement = new Element("exclude");
			excludeElement.addContent(exclude.toElement());
			return element;
		}

		public SpanQuery getInclude() {
			return include;
		}

		public SpanQuery getExclude() {
			return exclude;
		}
	}

	public static class SpanNearQuery extends SpanQuery {
		private SpanQuery[] clauses;
		private int slop;
		private boolean inOrder;

		public SpanNearQuery(Element element) throws Exception {
			slop = XMLUtil.getAttributeInteger("slop", element);
			inOrder = XMLUtil.getAttributeBooleanPrimitive("inorder", element);
			List<Element> children = XMLUtil.getChildren(element);
			SpanQuery[] clauses = new SpanQuery[children.size()];
			for (int x = 0; x < children.size(); x++) {
				clauses[x] = getSpanQuery(children.get(x));
			}
		}

		public SpanNearQuery(SpanQuery[] clauses, int slop, boolean inOrder) {
			this.clauses = clauses;
			this.slop = slop;
			this.inOrder = inOrder;
		}

		public Element toElement() throws Exception {
			Element element = new Element("spannearquery");
			XMLUtil.setAttribute("slop", slop, element);
			XMLUtil.setAttribute("inorder", inOrder, element);
			for (SpanQuery spanQuery : clauses) {
				element.addContent(spanQuery.toElement());
			}
			return element;
		}

		public SpanQuery[] getClauses() {
			return clauses;
		}

		public int getSlop() {
			return slop;
		}

		public boolean isInOrder() {
			return inOrder;
		}
	}

	public static class SpanFirstQuery extends SpanQuery {
		private final SpanQuery spanQuery;
		private final int end;

		public SpanFirstQuery(Element element) throws Exception {
			end = XMLUtil.getAttributeInteger("end", element);
			spanQuery = getSpanQuery(element);
		}

		public SpanFirstQuery(SpanQuery spanQuery, int end) {
			this.spanQuery = spanQuery;
			this.end = end;
		}

		public SpanQuery getSpanQuery() {
			return spanQuery;
		}

		public int getEnd() {
			return end;
		}

		public Element toElement() throws Exception {
			Element element = new Element("spanfirstquery");
			XMLUtil.setAttribute("end", end, element);
			element.addContent(spanQuery.toElement());
			return element;
		}
	}
}
